package
{
    import flash.desktop.NativeApplication;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Loader;
    import flash.events.Event;
    import flash.filesystem.File;
    import flash.geom.Matrix;
    import flash.geom.Point;
    import flash.net.URLRequest;
    import flash.system.System;
    import flash.ui.Keyboard;
    import flash.utils.Dictionary;
    import starling.animation.Transitions;
    import starling.animation.Tween;
    import starling.core.Starling;
    import starling.display.BlendMode;
    import starling.display.Image;
    import starling.display.Sprite;
    import starling.events.EnterFrameEvent;
    import starling.events.KeyboardEvent;
    import starling.events.Touch;
    import starling.events.TouchEvent;
    import starling.events.TouchPhase;

    public class Game extends Sprite
    {
        [Embed(source = "../media/default.jpg")]
        public static const DefaultImage:Class;

        /* for managing files */
        public var img_loader:Loader;
        public var img_filenames:Vector.<String>;
        public var file_idx:int = 0;

        /* for managing tweens */
        public var main_tween:Tween;
        public var tween_sequences:Vector.<int>;
        public var current_tween_sequence_idx:int = 0;
        public var need_to_call_next_tween:int = 0;

        /* tween settings */
        public var direction:Number = 0.01;
        public var tween_settings:Vector.<Number>;
        public var tween_settings_idx:int = 0;

        /* main image */
        public var main_image:Image;
        public var is_small_image:int = 0;
        public var x_pos:int = 0;
        public var y_pos:int = 0;
        public var image_width:int = 0;
        public var image_height:int = 0;
        public var bmp_zoom_scale:Number = 1.15;

        /* screen */
        public var current_screen_width:int = 0;
        public var current_screen_height:int = 0;
        public var half_width:int = 0;
        public var half_height:int = 0;

        public function Game()
        {
            img_loader = new Loader();

            reload();

            this.touchable = true;

            this.addEventListener(starling.events.Event.ADDED_TO_STAGE, onAddedToStage);
            this.addEventListener(TouchEvent.TOUCH, onTouch);

            var config_file:Dictionary = JSONfy.load_config();

            if (config_file["show_stats"] == "true")
            {
                trace("hardware mode: ", Starling.current.context.driverInfo);
                Starling.current.showStats = true;
            }
        }

        private function onAddedToStage(e:starling.events.Event):void
        {
            this.removeEventListener(starling.events.Event.ADDED_TO_STAGE, onAddedToStage);

            stage.addEventListener(starling.events.KeyboardEvent.KEY_UP, onKeyUp);
        }

        private function onKeyUp(e:starling.events.KeyboardEvent):void
        {
            switch (e.keyCode)
            {
                case Keyboard.F:
                    {
                        if (Starling.current.showStats == true)
                        {
                            Starling.current.showStats = false;
                        }
                        else
                        {
                            Starling.current.showStats = true;
                        }
                    }
                    break;
                case Keyboard.ESCAPE:
                    {
                        NativeApplication.nativeApplication.exit();
                    }
                    break;
                case Keyboard.N:
                    {
                        goto_next_change_image();
                    }
                    break;
                case Keyboard.R:
                    {
                        reload();
                    }
                    break;
                default:
                    break;
            }
        }

        private function onEnterFrame(event:starling.events.EnterFrameEvent):void
        {
            this.removeEventListener(starling.events.EnterFrameEvent.ENTER_FRAME, onEnterFrame);

            if (need_to_call_next_tween == 1)
            {
                need_to_call_next_tween = 0;

                nextTween();
            }
        }

        private function nextTween():void
        {
            // reset the tween sequence index
            if (current_tween_sequence_idx > tween_sequences.length - 1)
            {
                current_tween_sequence_idx = 0;
                tween_settings_idx = 0;
            }

            var tw_id:int = tween_sequences[current_tween_sequence_idx];
            var tw_setting:int = 0;
            var add_to_juggler:int = 0;

            if ( tw_id == TweenTypeConstants.FADETOZERO)
            {
                main_image.alpha = 1.0;

                //fade to zero
                tw_setting = tween_settings[tween_settings_idx];
                ++tween_settings_idx;

                main_tween.reset(main_image, tw_setting);
                main_tween.fadeTo(0);

                add_to_juggler = 1;
            }

            if (tw_id == TweenTypeConstants.FADETOONE)
            {
                main_image.alpha = 0.0;

                //fade to one
                tw_setting = tween_settings[tween_settings_idx];
                ++tween_settings_idx;

                main_tween.reset(main_image, tw_setting);
                main_tween.fadeTo(1);

                add_to_juggler = 1;
            }

            if (tw_id == TweenTypeConstants.SCAN)
            {
                // scan time
                var scan_time:Number = tween_settings[tween_settings_idx];
                ++tween_settings_idx;

                // scan transition id
                var scan_transition_id:Number = tween_settings[tween_settings_idx];
                ++tween_settings_idx;

                var scan_transition:String;

                if (scan_transition_id == 0.0)
                {
                    scan_transition = Transitions.EASE_IN_OUT;
                }

                main_tween.reset(main_image, scan_time, scan_transition);

                if (! (is_small_image == 1))
                {
                    if (image_width > image_height)
                    {
                        x_pos = 0;
                        y_pos = main_image.y;

                        if (direction < .5)// move the photo to the left
                        {
                            x_pos = -(image_width - current_screen_width);
                        }
                    }

                    if (image_height > image_width)
                    {
                        x_pos = main_image.x;
                        y_pos = 0;

                        if (direction < .5)// move the photo up
                        {
                            y_pos =  -(image_height - current_screen_height);
                        }
                    }

                    if (image_width == image_height && image_width > current_screen_width)
                    {
                        var ix_diff:int = image_width - current_screen_width;
                        x_pos = -( ix_diff);
                        y_pos = 0;
                    }

                    if (image_width == current_screen_width && image_height == current_screen_height)
                    {
                        main_image.x = 0;
                        main_image.y = 0;
                        x_pos = 0;
                        y_pos = 0;
                    }

                    main_tween.moveTo(x_pos, y_pos);
                }

                add_to_juggler = 1;
            }

            if (tw_id == TweenTypeConstants.ZOOM)
            {
                var x_diff:int = 0;
                var y_diff:int = 0;

                // zoom time
                tw_setting = tween_settings[tween_settings_idx];
                ++tween_settings_idx;

                main_tween.reset(main_image, tw_setting);

                //zoom scale
                var zoom_scale:Number = tween_settings[tween_settings_idx];
                ++tween_settings_idx;

                main_tween.scaleTo(zoom_scale);

                if (is_small_image)
                {
                    x_pos = half_width  - (image_width  * zoom_scale / 2);
                    y_pos = half_height - (image_height * zoom_scale / 2);
                }

                // if it is wide, center height
                if (image_width > current_screen_width)
                {
                    if (direction < .5)
                    {
                        y_diff = (image_height * zoom_scale) - current_screen_height;
                        y_pos  = - (y_diff);
                    }

                    if ( direction >= .5)
                    {
                        x_pos = main_image.x;
                        y_pos = 0;
                    }
                }

                // if it is tall, center width
                if (image_height > current_screen_height)
                {
                    if ( direction < .5)
                    {
                        x_diff = (image_width * zoom_scale) - current_screen_width;
                        x_pos  = - (x_diff);

                        y_pos = main_image.y;
                    }

                    if (direction >= .5)
                    {
                        x_pos = 0;
                        y_pos = main_image.y;
                    }
                }

                if (image_width == current_screen_width && image_height == current_screen_height)
                {
                    x_pos = 0;
                    y_pos = 0;
                }

                main_tween.moveTo(x_pos, y_pos);

                add_to_juggler = 1;
            }

            //
            if (add_to_juggler == 1)
            {
                main_tween.onComplete = nextTween;
                Starling.juggler.add(main_tween);
            }

            ++current_tween_sequence_idx;

            /* Special case(s) *
             *                 *
             *                 */

            if (tw_id == TweenTypeConstants.CHANGEIMAGE)
            {
                changeImage();

                // reset the index counter
                current_tween_sequence_idx = tween_sequences.length;
            }
        }

        private function goto_next_change_image():void
        {
            if (tween_sequences[ tween_settings_idx ] == TweenTypeConstants.CHANGEIMAGE)
            {
                return;
            }

            var next_change:int = -1;

            for (var i:int = current_tween_sequence_idx; i < tween_sequences.length; ++i)
            {
                if (tween_sequences[i] == TweenTypeConstants.CHANGEIMAGE)
                {
                    next_change = i;
                }
            }

            if (next_change == -1)
            {
                for (i = current_tween_sequence_idx; i < tween_sequences.length; ++i)
                {
                    if (tween_sequences[i] == TweenTypeConstants.CHANGEIMAGE)
                    {
                        next_change = i;
                    }
                }
            }

            if (next_change != -1)
            {
                current_tween_sequence_idx = next_change;
                tween_settings_idx = tween_settings.length;
                nextTween();
            }
        }

        private function reload():void
        {
            current_screen_width  = Starling.current.stage.stageWidth;
            current_screen_height = Starling.current.stage.stageHeight;
            half_width  = current_screen_width  / 2;
            half_height = current_screen_height / 2;

            if (main_tween)
            {
                Starling.juggler.remove(main_tween);
            }

            if (main_image)
            {
                this.removeChild(main_image);
            }

            main_image = Image.fromBitmap(new DefaultImage());
            main_image.touchable = false;
            main_image.blendMode = BlendMode.NONE;
            main_image.x = 0;
            main_image.y = 0;
            x_pos = 0;
            y_pos = 0;
            is_small_image = 0;

            if ( !main_tween )
            {
                main_tween = new Tween(main_image, 0.0);
            }

            img_filenames = new Vector.<String>();
            loadImageFilenames();
            JSONfy.load_tweens(this);

            file_idx = 0;

            // reset the index counter
            current_tween_sequence_idx = 0;
            tween_settings_idx = 0;

            need_to_call_next_tween = 1;

            this.addChild(main_image);

            this.addEventListener(EnterFrameEvent.ENTER_FRAME, onEnterFrame);

            trace("reloading game");
        }

        private function loadImageFilenames():void
        {
            var files:Array = flash.filesystem.File.applicationDirectory.getDirectoryListing();

            var length:int = files.length;
            for (var i:int = 0; i < length; ++i)
            {
                var filename:String = files[i].name;

                var sz:int = filename.length;

                if ( ! (sz > 0) )
                {
                    continue;
                }

                //Search for jpg and png but not gifs. Gifs are just too ugly.
                if (
                    ((filename.charAt(sz - 4) == '.' &&
                      filename.charAt(sz - 3) == 'j' &&
                      filename.charAt(sz - 2) == 'p' &&
                      filename.charAt(sz - 1) == 'g'))
                    ||
                    ((filename.charAt(sz - 5) == '.' &&
                      filename.charAt(sz - 4) == 'j' &&
                      filename.charAt(sz - 3) == 'p' &&
                      filename.charAt(sz - 2) == 'e' &&
                      filename.charAt(sz - 1) == 'g'))
                    ||
                    ((filename.charAt(sz - 4) == '.' &&
                      filename.charAt(sz - 3) == 'p' &&
                      filename.charAt(sz - 2) == 'n' &&
                      filename.charAt(sz - 1) == 'g'))
                    )
                {
                    if ( ! (filename == "default.jpg") )
                    {
                        img_filenames.push(filename);
                    }
                }
            }
        }

        private function onLoaded(onLoadedEvent:flash.events.Event):void
        {
            this.x_pos = 0;
            this.y_pos = 0;

            this.direction = Math.random();

            var original_bmp:Bitmap = onLoadedEvent.target.content as Bitmap;

            var texture_bitmap:Bitmap = original_bmp;

            var texture_width:int  = original_bmp.width;
            var texture_height:int = original_bmp.height;

            var original_width:int  = texture_width;
            var original_height:int = texture_height;

            is_small_image = 1;

            // if this is a big image, make a smaller version that's bigger than the display.
            // how much smaller is dependent on the scale we need for when we zoom in.
            if (original_width > current_screen_height || original_height > current_screen_height)
            {
                is_small_image = 0;

                // if image is wider than it is tall
                // scale the image height to be slightly taller than the screen height
                if (original_height < original_width)
                {
                    texture_width  = current_screen_height * (original_width / original_height);
                    texture_height = current_screen_height;
                }

                // if image is taller than it is wide
                // scale the image width to be slightly wider than the screen width
                if(original_width < original_height)
                {
                    texture_width  = current_screen_width;
                    texture_height = current_screen_width * (original_height / original_width);
                }

                if (original_width == original_height)
                {
                    texture_width  = current_screen_height * (original_width / original_height);
                    texture_height = current_screen_height;
                }

                // The bitmap will be larger than the texture. The texture will be sized down.
                // This helps with the zoom. If the image is really big, when we scale to 1.0
                // it'll zoom into the full size. Which is too big.
                var bmp_width:int  = texture_width  * bmp_zoom_scale;
                var bmp_height:int = texture_height * bmp_zoom_scale;

                var bmp_scale_down_factor:Number = (bmp_width / original_width);

                var M:Matrix = new Matrix();
                M.scale(bmp_scale_down_factor, bmp_scale_down_factor);

                var bmp_data:BitmapData = new BitmapData(bmp_width, bmp_height, true, 0x000000);
                bmp_data.draw(original_bmp, M, null, null, null, true);

                texture_bitmap = new Bitmap(bmp_data);
            }

            main_image = Image.fromBitmap(texture_bitmap);
            main_image.touchable = true;
            main_image.blendMode = BlendMode.NONE;

            main_image.width  = texture_width;
            main_image.height = texture_height;

            this.image_width  = texture_width;
            this.image_height = texture_height;

            if (is_small_image == 0 && direction >= .5)
            {
                if (image_width > image_height)
                {
                    main_image.x = -(image_width - current_screen_width);
                }

                if (image_height > image_width)
                {
                    main_image.y = -(image_height - current_screen_height);
                }
            }

            if (is_small_image == 1)
            {
                // center small images
                main_image.x = half_width  - (texture_width  / 2);
                main_image.y = half_height - (texture_height / 2);
            }

            this.addChild(main_image);
            nextTween();
        }

        private function changeImage():void
        {
            if (file_idx < img_filenames.length)
            {
                var filename:String = img_filenames[file_idx];

                trace("loading: ", filename);

                var urlReq:URLRequest = new URLRequest(filename);
                img_loader.contentLoaderInfo.addEventListener(flash.events.Event.COMPLETE, onLoaded);
                img_loader.load(urlReq);

                ++file_idx;
            }
        }

        private function onTouch(event:TouchEvent):void
        {
            var touch:Touch = event.getTouch(this, TouchPhase.BEGAN);
            if (touch)
            {
                var localPos:Point = touch.getLocation(this);
                trace("Touched object at position: " + localPos);
            }
        }
    }// end class Game
}

